/*
The surface-physics project: http://code.google.com/p/surface-physics/
Adds real world physics based on the Bullet physics engine, to bases in the Orbiter space
flight simulation software.

Written by Abhijit Nandy
License : Apache License 2.0


This file declares a common class for a pointer
that can  point at different type of objects(sub classed in AttachmentLibrary and ComponentLibrary).

AttachmentLibrary : contains primarily objects which are VESSELs controlled via attachment points
ComponentLibrary  : contains objects that do not require attachment points but may use it if necess.


		   Bump_BaseObject (parent)
            /          \
           /            \
	Bump_ATV		Bump_ExternalStaticGeometry (derived)


*/


#pragma once

//C++ STL used
#include <string>
#include <unordered_map>

#include "../Engine//PhysicsEngine.h"
#include "Bump_BulletBase.h"




//#include "BaseFactory.h"


extern PhysicsEngine *phyEngine;

extern char boutput[1000];

#define MAX_STRLEN 50



/**
 * The Bump_BaseObject to derive classes meant to control objects attached/part of a BulletBase
 * Objects of this class appear *inside* objects of Bump_BulletBase
 */
class Bump_BaseObject
{

//#pragma message("Bump_BaseObject.h included")

protected:

	//World transforms must not be shared here, use local variables and RAII

	bool physicsInited;


	//The containing Bump_BulletBase
	Bump_BulletBase *bumpBase;


public:

	char strObjectName[MAX_STRLEN];
	char className[MAX_STRLEN];

	/**
	 * Delete when inactive, flag, prevents removal by containing section if set
	 * This also prevents the current owning section of this object from being deleted
	 *
	 * This is required to prevent certain dynamic objects from being removed: such as
	 * a raycast vehicle based object. If this is not present then dynamic objects will be
	 * deleted when their owning section is deleted and reloaded at their initial position.
	 *
	 * But they may not have been in their initial position when deleted(being dynamic), thus user
	 * will see object in different position when he returns.
	 *
	 * By default its false to prevent objects from being deleted. Static derived classes should set it
	 * to true as well other objects which do not need to persist their position between loads.
	 */
	bool deleteIfInactive;

	/**
	 * freq is the number of sim steps for which prestep() or poststep() need not
	 * be called after it has been called in the current step. This can be INFINITY which means that
	 * prestep() & poststep() will never be called for that object
	 * Objects should set the update delay when inactive or when it need not receive updates for a
	 * few cycles. This prevents unnecessary function calls from the base, requesting updates.
	 *
	 */
	int mPreStepFrequency, mPostStepFrequency;

	/**
	 * Call this object's clbkFrozen() when base is frozen
	 * Useful for objects which are not outside & dependent on terrain. These
	 * can safely continue updating themselves.
	 */
	bool updateWhenFrozen;



	//this object is deleted by base if set
	bool  deleteMe;

	//This objects Orbiter handle if keeping such a reference is required
	OBJHANDLE hObjThis;

	
	typedef Bump_BaseObject * (*base_creator_fn)();
	typedef std::unordered_map<std::string, base_creator_fn> registry_map;
	
	static registry_map& registry();
    static Bump_BaseObject * instantiate(std::string const & name);
    static bool checkRegistry(std::string const & name);

    //Utility functions for children
    //void printHUD();




	//Constructor, destructor

	Bump_BaseObject();
	virtual ~Bump_BaseObject();  //must be virtual to call derived class dtor


	//Sometimes the hObj is already available so a search by hObj is not required
	//Such as while creating objects dynamically(see Bump_BulletBase::rangingPass())

	/**
	 * Create a new object meant to be injected into the Orbiter and Bullet world
	 * simultaneously
	 *
	 *	To deal with R6025 run-time error in Visual C++: Pure virtual function call
	 *	Call  DebugBreak() to break the debugger when this error is seen
	 *	http://support.microsoft.com/kb/125749
	 *
	 *	This function is not pure virtual, but this error has still been encountered once.
	 *
	 *	hObj is optional in declaration, NULL as default, some classes do not need hObj & can
	 *	search for the vessel insim if needed.
	 */
	virtual int		clbkSetClassCaps(InitialObjectData& initialData);


	/**
	 * Called before the Bullet sim step to apply forces
	 * Will be implemented by derived classes.
	 */
	virtual int		clbkPreStep(double SimT, double SimDT, double MJD);


	/**
	 * Updates(transforms) the Orbiter object according to changes in its Bullet object
	 * Will be implemented by derived classes.
	 *
	 * Called after Bullet sim step.
	 */
	virtual int		clbkPostStep(double SimT, double SimDT, double MJD);


	/**
	 * Called when this object should load its state from the any file(scenario or physics)
	 * The base will create this object as it encounters it and then call
	 * upon this object to read its parameters from the file
	 * clbkSetClassCaps() will not be called, but may be called by
	 * object from inside this function. Basically this function serves as the
	 * alternate initialization mechanism from file.
	 */
	virtual int		clbkLoadState(FILEHANDLE file);


	/**
	 * Called when this object can save its parameters to any file(scenario or physics)
	 * The object and class name has already been written
	 * END OBJECT will be added by base.
	 */
	virtual int		clbkSaveState(FILEHANDLE file);


	/**
	 * Called by the visualizer thread to render geometry in OpenGL window
	 */
	virtual int 	clbkPhysicsRender(void);


	/**
	 * Called before removal of this object midway in the sim. The dtor MUST free
	 * all memory and remove any rigid bodies from the physics world.
	 */
	virtual int 	clbkRemoveFromSim();


	/**
	 * Called when object must reset its state to that at sim start
	 * Its not yet clear if or when this may be needed as user cannot
	 * trigger a reset in-sim in Orbiter.
	 */
	virtual	int		clbkReset();


	/**
	 * Called to set focus to the primary rigid body and move the camera in the
	 * Visualizer window only. Is also called when focus changed in Orbiter window
	 * So the logic for shifting camera focus in the visualizer resides here.
	 *
	 */
	virtual void	clbkSetFocus();

};


struct Registrar
{
    Registrar(std::string name, Bump_BaseObject::base_creator_fn func)
    {
    	Bump_BaseObject::registry()[name] = func;
        oapiWriteLogV("Registering class %s", name.c_str());
    }
};







